<template>
  <q-layout view="hhh Lpr lff">
    <q-header bordered class="bg-primary text-white">
      <q-toolbar class="q-px-xs">
        <div class="self-stretch row no-wrap">
          <q-btn flat icon="menu" @click="toggleLeftDrawer" class="q-mr-sm" />
        </div>
        <q-avatar square v-if="props.showHeaderLogo">
          <img :src="props.webHeaderLogo" alt="header-logo" />
        </q-avatar>
        <q-toolbar-title>{{fx.packageInfo?.productName}}</q-toolbar-title>
        <simple-filter-select :options="langDropdown" :use-filter="false" :clearable="false" :model-value="lang"
          @update:modelValue="changeLocale" v-if="fx.globalCfg.supportLanguageSwitch" style="background-color: white"/>
        <div class="self-stretch row no-wrap">
          <q-btn flat icon="email" to="/comm/my/message">
            <q-badge style="top:1px" floating color="red" v-if="fx.unreadMsgNum.value !== 0">{{fx.unreadMsgNum}}</q-badge>
          </q-btn>
        </div>
        <div class="self-stretch row no-wrap" v-if="fx.ua">
          <q-btn flat icon="person" :label="$q.screen.lt.md ? '' : fx.ua.value.displayName" no-caps>
            <q-menu anchor="bottom right" self="top right" transition-show="none" transition-hide="none"
              class="bg-primary text-white" style="width: 320px" square :offset="[0, 5]">
              <div class="q-pa-md">
                <div class="text-h5 text-center">{{fx.ua.value.displayName}}</div>
                <div class="text-subtitle1 text-center q-pt-sm">{{fx.rr?.value.roleStr}}</div>
              </div>
              <q-separator />
              <div class="simple-border text-black bg-white q-pa-sm">
                <q-btn v-close-popup unelevated color="primary" to="/comm/my/my-profile">个人资料</q-btn>
                <q-btn v-close-popup unelevated color="primary" class="q-ml-sm" @click="changePassword">修改密码</q-btn>
                <q-btn dense unelevated icon="refresh" color="primary" class="q-ml-sm" title="刷新角色信息"
                  :loading="refreshingRoleRightInfo" @click="refreshRoleRightInfo">
                  <template v-slot:loading>
                    <q-spinner />
                  </template>
                </q-btn>

                <q-btn dense unelevated icon="cached" color="primary" class="q-ml-sm"
                  title="清除缓存. 某些情况下缓存在浏览器端的数据未能自动刷新,需要手工执行一下刷新."
                  @click="clearClientCache">
                  <template v-slot:loading>
                    <q-spinner />
                  </template>
                </q-btn>
                <q-btn v-close-popup unelevated class="float-right" color="negative" @click="logout">登出</q-btn>
              </div>
            </q-menu>
          </q-btn>
        </div>
      </q-toolbar>
    </q-header>

    <q-drawer v-model="showLeftDrawer" side="left" :width="260" bordered class="bg-grey-1"
      :mini="leftDrawerHoverState && leftDrawerMinState" @mouseover="leftDrawerHoverState = false"
      @mouseout="leftDrawerHoverState = true" :mini-to-overlay="leftDrawerMinState" show-if-above>
      <q-list>
        <template v-for="menuItem in sideMenuInfoFiltered">
          <q-expansion-item expand-separator v-if="menuItem.children?.length" :icon="menuItem.icon"
            :label="menuItem.label" :duration="200" :default-opened="checkIfNeedExpand(menuItem.children, route.path)"
            expand-icon="keyboard_arrow_down" :key="'main' + menuItem.id" group="sidemenu"
            :ref="(el)=>{refExpansionMenuItem(el, menuItem.id)}">
            <q-item clickable active-class="text-primary text-weight-bold bg-grey-4" :to="subMenuItem.to" :href="subMenuItem.href"
              v-for="subMenuItem in menuItem.children" :key="subMenuItem.id" dense :target="subMenuItem.href?'_blank':''">
              <q-item-section avatar class="q-ml-md">
                <q-icon :name="subMenuItem.icon" />
              </q-item-section>
              <q-item-section>{{subMenuItem.label}}</q-item-section>
            </q-item>
          </q-expansion-item>
          <q-item v-else clickable exact exact-active-class="text-primary text-weight-bold bg-grey-4" :to="menuItem.to"
            :key="'direct-' + menuItem.id">
            <q-item-section avatar>
              <q-icon :name="menuItem.icon" />
            </q-item-section>
            <q-item-section>{{menuItem.label}}</q-item-section>
          </q-item>
        </template>
      </q-list>
    </q-drawer>

    <q-page-container>
      <router-view  :key="fx.router.currentRoute.value.path" />
    </q-page-container>

    <q-footer bordered class="bg-grey-1 text-grey-9">
      <q-toolbar>
        <q-toolbar-title class="row">
          &copy; {{fx.packageInfo?.copyrightYear}}
          {{fx.packageInfo?.njtconfig.copyrightProprietor}}
          &nbsp;
          <a href="https://beian.miit.gov.cn/" target="blank">{{fx.packageInfo?.njtconfig.miiReg}}</a>
          <q-space />
          版本:
          <router-link to="/comm/cfg/updaterecord">{{fx.packageInfo?.version}}</router-link>
        </q-toolbar-title>
      </q-toolbar>
    </q-footer>
  </q-layout>
</template>
<script lang="ts">
export default {
  name: 'mainLayoutStd',
}
</script>
<script lang="ts" setup>
import {SideMenuItem, UserRoleRightInfo, GenericStatus} from '../defs/comm'
import {ref, computed, onBeforeUnmount, watch, reactive} from 'vue'
import {QExpansionItem, useQuasar} from 'quasar'
import _ from 'lodash'
// @ts-ignore
import njtWebHeaderLogo from '../assets/njt-web-header-logo.png'
import {useI18n} from 'vue-i18n'
import SimpleFilterSelect from 'src/lib/components/SimpleFilterSelect.vue'

const $q = useQuasar()
const fx = $f

const route = $f.router.currentRoute
interface PropsDef {
  //标题栏的log
  webHeaderLogo?: string
  //侧栏菜单定义
  sideMenuInfo: SideMenuItem[]
  //是否显示标题栏的LOGO
  showHeaderLogo?: boolean
  //是否使用OAuth2（影响登出的方式）
  useOauth2?: boolean

}

const props = withDefaults(defineProps<PropsDef>(), {
  webHeaderLogo: njtWebHeaderLogo,
  sideMenuInfo: () => [],
  showHeaderLogo: true,
  useOauth2: false,
  supportMultiLanguages: false
})

// region 侧方抽屉
const leftDrawerMinState = ref(false)
const showLeftDrawer = ref(false)
const leftDrawerHoverState = ref(false)

function toggleLeftDrawer() {
  if (!showLeftDrawer.value) {
    showLeftDrawer.value = true
  } else {
    leftDrawerMinState.value = !leftDrawerMinState.value
  }
}

//region语言切换
const {t, locale} = useI18n({useScope: 'global'})
let lang = ref(_.cloneDeep(locale.value))
// 语言选项数据源
let langDropdown = reactive([
  {
    value: 'zh-CN',
    label: '中文'
  },
  {
    value: 'en-US',
    label: 'English'
  },
  {
    value: 'ja-JP',
    label: '日本語'
  }
])
const changeLocale = function (e: string) {
  void $f.ui.messageBox({
    caption: t('操作确认'),
    text: t('切换语言会导致页面刷新，一些未保存的数据可能会丢失，确定继续吗？'),
    icon: 'Question',
    buttons: 'OkCancel',
    delayClose: true
  }).then((btn) => {
    if (btn === 'ok') {
      locale.value = e
      lang.value = e
      window.localStorage.setItem('lang', e)
      location.reload()
    }
  })
}

//endregion

function changePassword(){
  if (props.useOauth2) {
    $f.ui.showScreenLoading('请稍候...')
    $f.axios.get<string>('/comm/auth/get-change-password-page-url?reurl=' + encodeURIComponent(window.location.href))
      .then((res)=>{
        window.location.href = res.data
      })
      .catch((err) => {
        $f.ui.showNotifyFailed('获取OAuth2修改密码页链接失败: ' + $f.getAxiosErrMsg(err))
        console.error(err)
      })
      .finally(() => {
        $f.ui.hideScreenLoading()
      })
  }
  else {
    $f.router.push('/comm/auth/change-password?reurl=' + encodeURIComponent(route.value.path))
  }
}

function logout() {
  if ($f.ua) {
    $f.axios.post('/comm/auth/logout')
      .then(() => {
        $f.ua = null
        $f.rr = null
        $f.unreadMsgNum.value = 0
        localStorage.removeItem('ua')
        localStorage.removeItem('rr')
        localStorage.removeItem('unreadMsgNum')
        sessionStorage.clear()
        if (props.useOauth2) {
          $f.ui.showScreenLoading('登出中，请稍候...')
          $f.axios.get<string>('/comm/auth/get-logout-url')
            .then((resp) => {
              const urlToLogout = $f.misc.makeUrlWithQueryParam(resp.data, {reurl: $f.appCfg.websiteBaseUrl})
              window.location.href = urlToLogout
            })
            .catch((err) => {
              $f.ui.showNotifyFailed('获取OAuth2单点登出链接失败: ' + $f.getAxiosErrMsg(err))
              console.error(err)
            })
            .finally(() => {
              $f.ui.hideScreenLoading()
            })
        } else {
          $f.router.go(0)
        }
      })
      .catch((err) => {
        $f.ui.showNotifyFailed($f.getAxiosErrMsg(err))
      })
  }
}

// endregion

// region 刷新用户状态相关

const refreshingRoleRightInfo = ref(false)

function refreshRoleRightInfo() {
  refreshingRoleRightInfo.value = true
  $f.axios
    .get<UserRoleRightInfo>('comm/rr/get-my-role-right-info')
    .then((resp) => {
      if ($f.rr) {
        $f.rr.value = resp.data
      } else {
        $f.rr = ref(resp.data)
      }
      localStorage.setItem('rr', JSON.stringify(resp.data))
    })
    .catch((err) => {
      $f.ui.showNotifyFailed($f.getAxiosErrMsg(err))
    })
    .finally(() => {
      refreshingRoleRightInfo.value = false
    })
}

// 此方法清除一些localStorage里的下拉数据的缓存，要求客户端强行从服务器上获取新的列表数据，而不是提供If-Modified-Since从而返回304
function clearClientCache() {
  void $f.ui.messageBox({
    caption: '操作确认',
    text: '确定要清除缓存吗?',
    icon: 'Warning',
    buttons: 'OkCancel',
  }).then((btn) => {
    if (btn === 'ok') {
      let keysToClear: string[] = []
      for (let i = 0; i < localStorage.length; i++) {
        let key = localStorage.key(i)
        if (key && (key.startsWith('dropdown-data:') || key.startsWith('dropdown-ts:') || key.startsWith('dropdown-etag:'))) {
          keysToClear.push(key)
        }
      }
      _.each(keysToClear, (key) => {
        localStorage.removeItem(key)
      })
      window.location.reload()
    }
  })
}

function updateUserGenericStatus() {
  if($f.errorState.value!==0){
    return
  }
  if ($f.ua) {
    let userStateTimestamp = window.localStorage.getItem('userStateTimestamp')
    $f.axios
      .get<GenericStatus>('/comm/auth/get-generic-status')
      .then((resp) => {
        const data = resp.data
        $f.isAppReadonly.value = data.isAppReadonly
        if ($f.unreadMsgNum) {
          $f.unreadMsgNum.value = data.unreadMsgNum
        } else {
          $f.unreadMsgNum = ref(data.unreadMsgNum)
        }
        window.localStorage.setItem('unreadMsgNum', $f.unreadMsgNum.value.toString())

        if (userStateTimestamp !== String(data.userStateTimestamp)) {
          window.localStorage.setItem('userStateTimestamp', data.userStateTimestamp.toString())
          refreshRoleRightInfo()
        }
      })
      .catch((err) => {
        console.error('获取用户通用状态出错: ' + $f.getAxiosErrMsg(err))
      })
  }
}

let genericStatusPooling = setInterval(() => {
  updateUserGenericStatus()
}, 60000)

updateUserGenericStatus()

onBeforeUnmount(() => {
  if (genericStatusPooling) {
    clearInterval(genericStatusPooling)
  }
})

// endregion

// region 侧栏菜单相关

function checkIfNeedExpand(children: SideMenuItem[], path: string) {
  if (children) {
    for (const sideMenuItem of children) {
      if (sideMenuItem.to) {
        if (path.indexOf(sideMenuItem.to) === 0) {
          return true
        }
      }
    }
  }
  return false
}

const sideMenuInfoFiltered = computed(() => {
  let result: SideMenuItem[] = []
  for (const sideMenuItem of props.sideMenuInfo) {
    if (Array.isArray(sideMenuItem.children) && sideMenuItem.children.length) {
      let children = []
      for (const subMenuItem of sideMenuItem.children) {
        if (!subMenuItem.needRight || $f.hasRight(subMenuItem.needRight)) {
          children.push(subMenuItem)
        }
      }
      if (children.length) {
        const newMenuItem = Object.assign({}, sideMenuItem)
        newMenuItem.children = children
        result.push(newMenuItem)
      }
    } else {
      if (!sideMenuItem.needRight || $f.hasRight(sideMenuItem.needRight)) {
        result.push(Object.assign({}, sideMenuItem))
      }
    }
  }
  return result
})

const expansionMenuItems: Record<string, QExpansionItem> = {}

const refExpansionMenuItem = function (el: QExpansionItem, menuItemId: string) {
  expansionMenuItems[menuItemId] = el
}

watch(
  () => route.value.path,
  (currPath) => {
    for (const sidemenu of props.sideMenuInfo) {
      if (sidemenu.children && checkIfNeedExpand(sidemenu.children, currPath)) {
        expansionMenuItems[sidemenu.id]?.show()
        break
      }
    }
  },
)

// endregion

</script>
